package br.ucb.dao.impl;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import br.ucb.conexao.Conexao;
import br.ucb.dao.EntidadeDAO;
import br.ucb.entidade.Entidade;
import br.ucb.excecao.RegrasException;

public abstract class AbstractEntidadeDAO_1<E extends Entidade> implements EntidadeDAO<E> {

	protected String table;  

	public AbstractEntidadeDAO_1(){  
		setTable();  
	}  
	
	public E findByKey(E entidade) throws RegrasException {
		String tabela = getTable();
		StringBuffer SQL_SELECT = new StringBuffer();
		
		SQL_SELECT.append("SELECT * FROM "+tabela+" WHERE 1=1");
		List<Object> args = doPreparedStatement(entidade, SQL_SELECT);
		
		PreparedStatement ps=null;
		ResultSet resultado=null;
		E retorno = null;
		try {
			ps = Conexao.getConexao().prepareStatement(SQL_SELECT.toString());
			for (int i = 0; i < args.size(); i++) {
				ps.setObject(i+1,args.get(i));
			}
			resultado = ps.executeQuery();

			retorno = retornaEntidades(resultado);
			
			ps.close();
			resultado.close();
			Conexao.closeConexao();
		} catch (SQLException e) {
			throw new RegrasException(e.getMessage());
		}
		return retorno;
	}

	public List<E> find(E entidade) throws RegrasException {
		StringBuffer select = new StringBuffer();

		select.append("SELECT * FROM "+getTable()+" WHERE 1=1");
		List<Object> args = doPreparedStatement(entidade, select);

		PreparedStatement ps;
		ResultSet resultado = null;
		try {
			ps = Conexao.getConexao().prepareStatement(select.toString());
			for (int i = 1; i <= args.size(); i++) {
				ps.setObject(i,args.get(i-1));
			}
			resultado = ps.executeQuery();
		} catch (SQLException e) {
			throw new RegrasException(e.getMessage());
		}
		List<E> list = retornaListaEntidades(resultado);
		Conexao.closeConexao();
		return list;
	}
	
	public List<E> findAll() throws RegrasException{
		StringBuffer SQL_SELECT = new StringBuffer();
		
		SQL_SELECT.append("SELECT * FROM "+getTable()+";");
		
		PreparedStatement ps;
		ResultSet resultado = null;
		try {
			ps = Conexao.getConexao().prepareStatement(SQL_SELECT.toString());
			resultado = ps.executeQuery();
		} catch (SQLException e) {
			throw new RegrasException(e.getMessage());
		}
		List<E> list = retornaListaEntidades(resultado);
		Conexao.closeConexao();
		return list;
	}
	
	public Boolean update(E entidade) throws RegrasException  {
		List<Object> args = new ArrayList<Object>();
		PreparedStatement ps = null;
		
		try {
			ps = Conexao.getConexao().prepareStatement(doUpdate(entidade, args));
			for(int i=1; i <= args.size(); i++){
				ps.setObject(i,args.get(i-1));
			}
			ps.executeUpdate();
		} catch (SQLException e) {
			throw new RegrasException(e.getMessage());
		}
		Conexao.closeConexao();
		return true;
	}

	public Boolean insert(E entidade) throws RegrasException  {
		StringBuffer insert = new StringBuffer();
		StringBuffer insertValues = new StringBuffer();
		List<Object> args = getInsertValues(entidade, insertValues);

		insert.append("INSERT INTO "+getTable()+" ("+getTableValues(entidade)+") values("+insertValues+");");

		PreparedStatement ps = null;

		try {
			ps = Conexao.getConexao().prepareStatement(insert.toString());
			for(int i=1; i <= args.size(); i++){
				ps.setObject(i,args.get(i-1));
			}
			ps.executeUpdate();
		} catch (SQLException e) {
			if(e.getErrorCode()==1062)
				throw new RegrasException("J� existe um usu�rio com esse CPF");
			else
				throw new RegrasException(e.getMessage());
		}
		Conexao.closeConexao();
		return true;
	}

	public Boolean remove(E entidade) throws RegrasException {
		StringBuffer remove = new StringBuffer();

		remove.append("DELETE FROM "+getTable()+" WHERE 1=1");
		List<Object> args = doPreparedStatement(entidade, remove);

		PreparedStatement ps;
		try {
			ps = Conexao.getConexao().prepareStatement(remove.toString());
			for (int i = 1; i <= args.size(); i++) {
				ps.setObject(i,args.get(i-1));
			}
			ps.executeUpdate();
		} catch (SQLException e) {
			throw new RegrasException(e.getMessage());
		}
		Conexao.closeConexao();
		return true;
	}

	protected abstract String doUpdate(E entidade, List<Object> args);
	
	protected abstract List<Object> doPreparedStatement(E entidade, StringBuffer query);

	protected abstract List<E> retornaListaEntidades(ResultSet resultado);
	
	protected abstract E retornaEntidades(ResultSet resultado);  //adicionei **************

	protected abstract List<Object> getInsertValues(E entidade, StringBuffer sql);

	protected abstract String getTableValues(E entidade);

	abstract protected void setTable();

	public String getTable() {
		return table;
	}
}
